Раздел: Идеи и принципы программирования

Второй уровень сложности

1. Сравнение декларативного и императивного программирования.
* Императивное (Лекции 1, 13): Мы даем компьютеру последовательность команд (приказов), детально описывая алгоритм (как сделать). Используем циклы, присваивания, изменение состояния переменных.
* Пример: Цикл for с append для заполнения списка.
* Декларативное (Лекция 13): Мы описываем результат (что хотим получить), скрывая детали реализации.
* Пример: Списочное включение [x for x in A] или запрос A[A>5] (как в SQL или numpy).
* Сравнение: Императивный стиль дает полный контроль над исполнением, но код длиннее и сложнее. Декларативный стиль лаконичнее и понятнее (ближе к человеческому языку или математике), но требует поддержки со стороны языка или библиотек.

2. Однострочники, кванторы и коллекции как основа декларативного программирования.
* Ответ (Лекции 1, 2, 13):
* Однострочники (List Comprehensions): Позволяют записать создание и фильтрацию коллекций в одну строку, описывая формулу результата, а не процесс добавления элементов.
* Кванторы (all, any): Позволяют избежать сложных циклов с флагами (if flag: break). Мы просто спрашиваем: «Все ли элементы удовлетворяют условию?» (all) или «Хотя бы один?» (any).
* Коллекции (Set, Dict): Операции над множествами (пересечение, разность) позволяют избежать вложенных циклов и условий.
* Вывод: Использование этих трех инструментов позволяет писать код, отвечающий на вопрос «Что?», а не «Как?», что и является сутью декларативного подхода.

3. Идея динамического программирования.
* Ответ (Лекции 4, 5): Это метод решения сложных задач путем разбиения их на более простые подзадачи того же типа.
* Ключевые компоненты:
1. Рекурсия: Сводит большую задачу к меньшим (например, fib(n) к fib(n-1) и fib(n-2)).
2. Кеш (Мемоизация): Запоминание результатов решенных подзадач в словаре, чтобы не вычислять их повторно.
* Пример: Числа Фибоначчи, быстрое возведение в степень.

4. Динамика по подотрезкам как разновидность динамического программирования.
* Ответ (Лекция 5): Это применение динамического программирования к задачам на строках или списках, где «подзадача» определяется уменьшением длины рассматриваемого фрагмента (подотрезка).
* Суть: Мы отрезаем элементы с краев строки/массива и решаем задачу для оставшейся части.
* Примеры: Поиск палиндрома максимальной длины (сравнение крайних букв), поиск максимального квадрата из нулей в матрице.
* Ключ в кеше: Обычно это кортеж границ (Left, Right) или сама подстрока/подматрица (если позволяет язык).

5. Идея функционального программирования.
* Ответ (Лекция 6): Парадигма, в которой процесс вычисления трактуется как вычисление значений функций в математическом понимании.
* Ключевые черты:
1. Функции высших порядков: Функции могут принимать другие функции как аргументы и возвращать их (например, map(func, list)).
2. Анонимные функции (lambda): Использование функций без имени для одноразовых операций.
3. Отсутствие побочных эффектов: В идеале функции не меняют глобальное состояние.
4. Вместо циклов используются рекурсия или функции map, filter, reduce.

6. Идея аспектно-ориентированного программирования (АОП).
* Ответ (Лекция 7): Парадигма, направленная на разделение основной бизнес-логики (математической сути) и сквозной функциональности (технических аспектов).
* Пример: У нас есть функция вычисления числа Фибоначчи (суть). Нам нужно добавить кеширование, логирование, проверку прав доступа (аспекты).
* Реализация в Python: Декораторы (@cache, @log). Мы не захламляем код функции техническими деталями, а «навешиваем» их снаружи.

7. Принципы объектно-ориентированного программирования (ООП).
* Ответ (Лекции 7, 8):
1. Абстракция: Выделение значимых свойств объекта.
2. Инкапсуляция: Объединение данных и методов в классе, сокрытие внутренней реализации (использование self).
3. Наследование: Возможность создавать новые классы на основе существующих.
4. Полиморфизм: Способность объектов с одинаковой спецификацией иметь различную реализацию (в Python реализуется через «утиную типизацию»).
5. Агрегация: Создание составных объектов (объект содержит внутри себя другие объекты).

8. «Утиная» типизация.
* Ответ (Лекция 7): Принцип в Python: «Если это выглядит как утка, плавает как утка и крякает как утка, то это, вероятно, и есть утка».
* Суть: Питону не важен тип объекта, ему важно, есть ли у объекта нужный метод или атрибут.
* Пример: Функция print(A) сработает для любого объекта A, если у него есть метод __str__, неважно, число это, список или пользовательский класс Point.

9. Множественное наследование.
* Ответ (Лекция 9): Возможность класса иметь более одного родительского класса.
* Синтаксис: class Child(Parent1, Parent2):
* Проблема: «Ромбовидное наследование» (когда предки имеют общего предка).
* Решение: В Python используется алгоритм линеаризации MRO (Method Resolution Order), который определяет порядок поиска методов (доступен через Class.mro()). Используется функция super().

10. Копирование по ссылке и значению. Что такое поверхностное и глубокое клонирование.
* Ответ (Лекции 3, 5, 10):
* По значению: Передаются неизменяемые типы (числа, строки). Создается копия данных.
* По ссылке: Передаются изменяемые типы (списки, словари, объекты). Передается адрес в памяти, изменения внутри функции влияют на оригинальный объект.
* Поверхностное клонирование (copy.copy): Создает новый объект-контейнер, но элементы внутри остаются ссылками на старые объекты. (Если изменить вложенный список, он изменится и в копии, и в оригинале).
* Глубокое клонирование (copy.deepcopy): Рекурсивно копирует объект и все вложенные в него объекты. Создает полностью независимую копию.

11. Индексаторы.
* Ответ (Лекции 10, 13): Механизм, позволяющий экземпляру класса вести себя как список или словарь, то есть обращаться к данным через квадратные скобки [].
* Реализация: Перегрузка магических методов __getitem__(self, index) (чтение) и __setitem__(self, index, value) (запись).
* Пример: fib[10] вернет 10-е число Фибоначчи, если в классе реализован __getitem__.

12. Генераторы.
* Ответ (Лекция 11): Это функции, которые могут приостанавливать свое выполнение, возвращая промежуточное значение, и затем возобновлять работу с того же места.
* Ключевое слово: yield (вместо return).
* Преимущество: Экономят память, так как не хранят весь список значений сразу, а вычисляют их по одному по мере необходимости (ленивые вычисления).
* Использование: next(gen) или в цикле for.

13. Идея асинхронного программирования.
* Ответ (Лекция 14): Выполнение задач в режиме, когда программа не блокируется в ожидании завершения долгой операции (например, ввода-вывода), а переключается на выполнение других задач.
* Суть: Иллюзия параллельности. Задачи (Tasks) передают управление друг другу.
* Инструменты: Ключевые слова async (объявление корутины), await (ожидание результата), библиотека asyncio, цикл событий (Event Loop).

← Меню